﻿// <copyright file="RainbowColorPicker.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2009 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2009-06-10</date>
// <summary>OpenWPFChart library.
// ColorPickerControls. RainbowColorPicker Control.</summary>
// <revision>$Id$</revision>

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace OpenWPFChart.Helpers.ChooseColorDialog
{
	/// <summary>
	/// RainbowColorPicker Control.
	/// </summary>
	/// <remarks>
	/// This control is the composition of RainbowBox and LuminositySlider controls.
	/// </remarks>
	[TemplatePart(Name = "PART_RainbowBox", Type = typeof(RainbowBox))]
	[TemplatePart(Name = "PART_LuminositySlider", Type = typeof(LuminositySlider))]
	public class RainbowColorPicker : Control
	{
		/// <summary>
		/// Initializes the <see cref="RainbowColorPicker"/> class.
		/// </summary>
		static RainbowColorPicker()
		{
			DefaultStyleKeyProperty.OverrideMetadata(typeof(RainbowColorPicker)
				, new FrameworkPropertyMetadata(typeof(RainbowColorPicker)));
		}

		#region Named Parts
		RainbowBox rainbowBox;
		LuminositySlider luminositySlider;
		#endregion Named Parts

		/// <summary>
		/// Gets the named parts.
		/// When overridden in a derived class, is invoked whenever application code or 
		/// internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate"/>.
		/// </summary>
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();

			rainbowBox = Template.FindName("PART_RainbowBox", this) as RainbowBox;
			luminositySlider = Template.FindName("PART_LuminositySlider", this) as LuminositySlider;
			if (luminositySlider != null)
			{
				luminositySlider.SelectedColorChanged += luminositySlider_SelectedColorChanged;
				SetConstituentControlsColor(SelectedColor);
			}
		}

		/// <summary>
		/// Handles the SelectedColorChanged event of the luminositySlider control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="ovp.WPFGears.SelectedColorChangedEventArgs"/> instance containing the event data.</param>
		void luminositySlider_SelectedColorChanged(object sender, SelectedColorChangedEventArgs e)
		{
			SelectedColor = e.Color;
		}

		/// <summary>
		/// Sets the color of the constituent controls, i.e. rainbowBox and luminositySlider.
		/// </summary>
		/// <param name="color">The color.</param>
		void SetConstituentControlsColor(Color color)
		{
			if (rainbowBox == null)
				return;
			Debug.Assert(luminositySlider != null, "luminositySlider != null");

			// Detach the SelectedColorChanged event handler to prevent from recursion.
			luminositySlider.SelectedColorChanged -= luminositySlider_SelectedColorChanged;

			// Try to set the color provided.
			if (rainbowBox.TrySetSelectedColor(color))
			{ // Set luminositySlider value with the Luminosity and, so, the SelectedColor.
				HSL hsl = new HSL(color);
				luminositySlider.Value = luminositySlider.Minimum
					+ hsl.Luminance * (luminositySlider.Maximum - luminositySlider.Minimum);
			}

			// Update the SelectedColor.
			SelectedColor = luminositySlider.SelectedColor;

			// Attach back the SelectedColorChanged event handler.
			luminositySlider.SelectedColorChanged += luminositySlider_SelectedColorChanged;
		}

		#region SelectedColor
		/// <summary>
		/// SelectedColor backing DependencyProperty.
		/// </summary>
		private static readonly DependencyProperty SelectedColorProperty
			= DependencyProperty.Register("SelectedColor", typeof(Color), typeof(RainbowColorPicker),
				new FrameworkPropertyMetadata(Colors.Transparent
					, FrameworkPropertyMetadataOptions.AffectsRender 
						| FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
					, SelectedColorPropertyChanged));
		/// <summary>
		/// Gets or sets the selected color.
		/// </summary>
		/// <value>The color selected.</value>
		public Color SelectedColor
		{
			get { return (Color)GetValue(SelectedColorProperty); }
			set { SetValue(SelectedColorProperty, value); }
		}
		/// <summary>
		/// SelectedColorProperty changed event handler.
		/// </summary>
		/// <param name="d">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> 
		/// instance containing the event data.</param>
		static void SelectedColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RainbowColorPicker ths = d as RainbowColorPicker;
			if (ths == null || ths.luminositySlider == null)
				return;

			Color newColor = (Color)(e.NewValue);
			if (newColor == ths.luminositySlider.SelectedColor)
				return; // Color is set internally, nothing to do.

			ths.SetConstituentControlsColor(newColor);
			ths.RaiseEvent(new SelectedColorChangedEventArgs(newColor, SelectedColorChangedEvent, ths));
		}
		#endregion SelectedColor

		#region SelectedColorChangedEvent
		/// <summary>
		/// SelectedColorChangedEvent backing RoutedEvent.
		/// </summary>
		public static readonly RoutedEvent SelectedColorChangedEvent
			= EventManager.RegisterRoutedEvent("SelectedColorChanged", RoutingStrategy.Bubble
				, typeof(SelectedColorChangedEventHandler), typeof(RainbowColorPicker));
		/// <summary>
		/// SelectedColorChangedEvent accessors.
		/// </summary>
		public event SelectedColorChangedEventHandler SelectedColorChanged
		{
			add { AddHandler(SelectedColorChangedEvent, value); }
			remove { RemoveHandler(SelectedColorChangedEvent, value); }
		}
		#endregion SelectedColorChangedEvent
	}
}
